﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data.Common;
using Bzure.Common.Data;

namespace Bzure.Common.Transactions
{
    public class ConnectionCompare
    {

        /// <summary>
        /// 数据库
        /// </summary>
        public string Database { get; set; }
        /// <summary>
        /// 数据源
        /// </summary>
        public string DataSource { get; set; }
        public DbConnection Connection { get; set; }
        public bool Compare(ConnectionCompare ConnectionCompare)
        {
            return string.Equals(this.Database, ConnectionCompare.Database, StringComparison.OrdinalIgnoreCase)
                && string.Equals(this.DataSource, ConnectionCompare.DataSource, StringComparison.OrdinalIgnoreCase);
        }
    }
    /// <summary>
    /// 事务组件
    /// </summary>
    /// 
    public sealed class BizTransaction
    {
        List<ITransactionFactor> TransactionFactors;
        public Guid TransactionID { get; private set; }
        ConnectionCompare CurrentConnectionCompare;
        TransactionContext TransactionContext;

        private BizTransaction()
        {
            this.TransactionID = Guid.NewGuid();
            TransactionFactors = new List<ITransactionFactor>();
            this.CurrentConnectionCompare = default(ConnectionCompare);
        }
        /// <summary>
        /// 注册事务因子
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="TransactionProvider"></param>
        /// <param name="hander"></param>

        public void RegisterFactor(ITransactionFactor factor)
        {
            TransactionFactors.Add(factor);
        }
        //public void RegisterFactor<Contract, T>(TransactionFactor<Contract, T> factor) where Contract : ITransactionSupport
        //{
        //    TransactionFactors.Add(factor);
        //}
        public void RegisterEntityFactor(string ProviderName, Func<IEntityRequestProcess, Action<Action<IEntityRequestProcess, EntityPostRequest>>> func)
        {
            IEntityRequestProcess orderProcessor = Actor.Public.BuildEntityProcessor(ProviderName);
            TransactionFactor<IEntityRequestProcess, Action<IEntityRequestProcess, EntityPostRequest>> orderFactor = new TransactionFactor<IEntityRequestProcess, Action<IEntityRequestProcess, EntityPostRequest>>(orderProcessor);
            orderFactor.ActionBody = (IEntityRequestProcess contract, EntityPostRequest request) =>
            {
                contract.UpdateEntity(request);
            };
            orderFactor.Action = func(orderProcessor);
            this.RegisterFactor(orderFactor);
        }
        /// <summary>
        /// 创建并开始事务
        /// </summary>
        /// <returns></returns>
        public static BizTransaction BeginTransaction()
        {
            return new BizTransaction();
        }
        /// <summary>
        /// 提交事务
        /// </summary>
        /// <returns>事务执行是否成功</returns>
        public bool TryCommit()
        {
            //验证所有的事务因子, 并产生事务数据库连接
            this.TransactionFactors.ForEach(this.FactorValidation);

            using (DbConnection Connection = this.CurrentConnectionCompare.Connection)
            {
                Connection.Open();
                using (DbTransaction transaction = Connection.BeginTransaction())
                {
                    try
                    {
                        TransactionContext = new TransactionContext()
                        {
                            TransactionID = this.TransactionID,
                            Connection = Connection,
                            Transaction = transaction
                        };

                        this.TransactionFactors.ForEach(this.TryExecuteFactor);
                        transaction.Commit();

                        return true;
                    }
                    catch
                    {
                        transaction.Rollback();
                        return false;
                    }
                }
            }
        }
        void FactorValidation(ITransactionFactor factor)
        {

            #region 验证事务因子的数据连接是否一致
            DbConnection connection = factor.FactorHost.CreateConnection();
            if (connection == default(DbConnection))
                throw new ArgumentNullException(string.Format("事务接口提供者没有创建有效地数据连接:{0}", factor.FactorHost.GetType()));
            ConnectionCompare ConnectionCompare = new ConnectionCompare()
            {
                Database = connection.Database,
                DataSource = connection.DataSource,
                Connection = connection
            };
            //第一个事务处理者
            if (this.CurrentConnectionCompare == default(ConnectionCompare))
            {
                this.CurrentConnectionCompare = ConnectionCompare;
            }
            else
            {
                if (this.CurrentConnectionCompare.Compare(ConnectionCompare))
                {
                    this.CurrentConnectionCompare = ConnectionCompare;
                }
                else
                {
                    throw new ApplicationException("事务因子的数据连接一致性不够");
                }
            }
            #endregion
        }
        void TryExecuteFactor(ITransactionFactor factor)
        {
            factor.FactorHost.TransactionContext = this.TransactionContext;
            factor.Execute();
            factor.FactorHost.TransactionContext = default(ITransactionContext);
        }
    }
}
